package com.origin.chaos.framework.core.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: tao.ding
 * @date 2021-07-02
 */
public class ImageUtil {

    /**
     * {@link Color}信息缓存
     * <p>例如，黑色的INT值(-16777216) -> {"colorInt": -16777216, "rgbStr": "rgb(0,0,0)", "hexStr": "#000000"}</p>
     */
    private static final Map<Integer, ColorInfo> COLOR_INFO_CACHE = new ConcurrentHashMap<>(256);

    /**
     * {@link Color}的RGB字符串转int值的缓存
     * <p>例如，黑色 rgb(0,0,0) -> int值是(-16777216) </p>
     */
    private static final Map<String, Integer> COLOR_RGB_STR_TO_INT_CACHE = new ConcurrentHashMap<>(256);

    /**
     * {@link Color}的RGB 16进制字符串转int值的缓存
     * <p>例如，黑色 #000000 -> int值是(-16777216) </p>
     */
    private static final Map<String, Integer> COLOR_HEX_STR_TO_INT_CACHE = new ConcurrentHashMap<>(256);


    /**
     * 颜色信息
     */
    private static class ColorInfo {
        /**
         * 颜色INT值,例如黑色(-16777216)
         */
        private Integer colorInt;

        /**
         * 颜色RGB字符串,例如黑色 rgb(0,0,0)
         */
        private String rgbStr;

        /**
         * 颜色RGB 16进制字符串,例如黑色 #000000
         */
        private String hexStr;

        public ColorInfo(Integer colorInt, String rgbStr, String hexStr) {
            this.colorInt = colorInt;
            this.rgbStr = rgbStr;
            this.hexStr = hexStr;
        }
    }

    /**
     * 根据Color对应的int获取相应的RGB 16进制字符串，并进行双向缓存
     * <p>例如，黑色 int值(-16777216) -> #000000</p>
     *
     * @param colorRgbInt
     * @return
     */
    public static String colorIntToHexString(int colorRgbInt) {
        return getColorInfoByRgbInt(colorRgbInt).hexStr;
    }

    /**
     * 根据Color对应的int获取相应的RGB字符串，并进行双向缓存
     * <p>例如，黑色 int值(-16777216) -> rgb(0,0,0)</p>
     *
     * @param colorRgbInt
     * @return
     */
    public static String colorIntToRgbString(int colorRgbInt) {
        return getColorInfoByRgbInt(colorRgbInt).rgbStr;
    }

    /**
     * 根据Color对应的int获取相应的颜色信息，并进行双向缓存
     *
     * @param colorRgbInt
     * @return
     */
    private static ColorInfo getColorInfoByRgbInt(int colorRgbInt) {
        Integer key = colorRgbInt;
        if (COLOR_INFO_CACHE.containsKey(key)) {
            return COLOR_INFO_CACHE.get(key);
        }
        Color color = new Color(colorRgbInt);
        // rgb字符串
        String rgbStr = String.format("rgb(%s,%s,%s)", color.getRed(), color.getGreen(), color.getBlue());
        // rgb 16进制字符串
        String hexStr = "#" + Integer.toHexString(color.getRed()) + Integer.toHexString(color.getGreen()) + Integer.toHexString(color.getBlue());
        ColorInfo colorInfo = new ColorInfo(colorRgbInt, rgbStr, hexStr);
        COLOR_INFO_CACHE.put(key, colorInfo);
        COLOR_RGB_STR_TO_INT_CACHE.put(rgbStr, key);
        COLOR_HEX_STR_TO_INT_CACHE.put(hexStr, key);
        return colorInfo;
    }

    /**
     * 根据RGB字符串获取相应的Color对应int值,并双向缓存
     * <p>例如，黑色 rgb(0,0,0) -> int值是(-16777216) </p>
     *
     * @param rgbString
     * @return
     */
    public static Integer rgbStringToColorInt(String rgbString) {
        if (COLOR_RGB_STR_TO_INT_CACHE.containsKey(rgbString)) {
            return COLOR_RGB_STR_TO_INT_CACHE.get(rgbString);
        }
        String[] simpleRgbStringSplit = rgbString.replace("rgb(", "").replace(")", "").split(",");
        int r = Integer.parseInt(simpleRgbStringSplit[0]);
        int g = Integer.parseInt(simpleRgbStringSplit[1]);
        int b = Integer.parseInt(simpleRgbStringSplit[2]);
        Integer intValue = new Color(r, g, b).getRGB();
        COLOR_RGB_STR_TO_INT_CACHE.put(rgbString, intValue);
        // rgb 16进制字符串
        String hexString = "#" + Integer.toHexString(r) + Integer.toHexString(g) + Integer.toHexString(b);
        COLOR_HEX_STR_TO_INT_CACHE.put(hexString, intValue);
        ColorInfo colorInfo = new ColorInfo(intValue, rgbString, hexString);
        COLOR_INFO_CACHE.put(intValue, colorInfo);
        return intValue;
    }

    /**
     * 根据RGB 16进制字符串获取相应的Color对应int值,并双向缓存
     * <p>例如，黑色 #000000 -> int值是(-16777216) </p>
     *
     * @param hexString
     * @return
     */
    public static Integer hexStringToColorInt(String hexString) {
        if (COLOR_HEX_STR_TO_INT_CACHE.containsKey(hexString)) {
            return COLOR_HEX_STR_TO_INT_CACHE.get(hexString);
        }
        int r = Integer.parseInt(hexString.substring(1, 3), 16);
        int g = Integer.parseInt(hexString.substring(3, 5), 16);
        int b = Integer.parseInt(hexString.substring(5), 16);
        Integer intValue = new Color(r, g, b).getRGB();
        COLOR_HEX_STR_TO_INT_CACHE.put(hexString, intValue);
        // rgb字符串
        String rgbString = "rgb(" + r + "," + g + "," + b + ")";
        COLOR_RGB_STR_TO_INT_CACHE.put(rgbString, intValue);
        ColorInfo colorInfo = new ColorInfo(intValue, rgbString, hexString);
        COLOR_INFO_CACHE.put(intValue, colorInfo);
        return intValue;
    }

    /**
     * RGB INT 值数组转RGB 16进制字符串数组
     *
     * @param rgbIntArr
     * @return
     */
    public static String[][] rgbIntArrToRgbHexArr(int[][] rgbIntArr) {
        String[][] stringArr = new String[rgbIntArr.length][rgbIntArr[0].length];
        for (int i = 0; i < rgbIntArr.length; i++) {
            for (int j = 0; j < rgbIntArr[i].length; j++) {
                stringArr[i][j] = colorIntToHexString(rgbIntArr[i][j]);
            }
        }
        return stringArr;
    }


    /**
     * 获取BufferedImage
     *
     * @param source
     * @return
     */
    public static BufferedImage getBufferedImage(int[][] source) {
        final int height = source.length;
        final int width = source[0].length;
        int[] data = getImageRgbData(source, width, height);
        return getBufferedImage(data, width, height);
    }

    /**
     * 获取图片的字节数组
     *
     * @param source
     * @return
     */
    public static byte[] getBufferedImageBytes(int[][] source) {
        BufferedImage bufferedImage = getBufferedImage(source);
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            ImageIO.write(bufferedImage, "png", outputStream);
            return outputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new IllegalArgumentException("生成图片字节数组失败");
    }

    /**
     * 将二维的图片RGB数据转换为一维数组
     *
     * @param source
     * @return
     */
    public static int[] getImageRgbData(int[][] source, int width, int height) {

        int[] data = new int[width * height];
        for (int i = 0; i < height; i++) {
            System.arraycopy(source[i], 0, data, i * width, width);
        }
        return data;
    }

    /**
     * RGB一维数组转换为BufferedImage
     *
     * @param data
     * @param width
     * @param height
     * @return
     */
    public static BufferedImage getBufferedImage(int[] data, int width, int height) {
        BufferedImage bf = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        bf.setRGB(0, 0, width, height, data, 0, width);
        return bf;
    }

    /**
     * 获取图片RGB二维数组
     *
     * @param filePathName
     * @return
     * @throws IOException
     */
    public static int[][] getImageRgbData(String filePathName) throws IOException {
        File file = new File(filePathName);
        BufferedImage bf = ImageIO.read(file);
        int width = bf.getWidth();
        int height = bf.getHeight();
        int[] data = new int[width * height];
        bf.getRGB(0, 0, width, height, data, 0, width);
        int[][] arr = new int[height][width];
        for (int i = 0; i < height; i++) {
            if (width >= 0) {
                System.arraycopy(data, i * width, arr[i], 0, width);
            }
        }
        return arr;
    }

}
